package edu.nf.db.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ServiceLoader;

/**
 * @Author lzp
 * @Date 2024-05-09
 * Bean反射工具类
 */
public class BeanProcessor {

    /**
     * 基于SPI加载所有TypeHandler实现
     */
    private final static ServiceLoader<TypeConverter> loader = ServiceLoader.load(TypeConverter.class);

    /**
     * 根据结果集创建Bean实例
     */
    public static <T> T createBean(ResultSet rs, Class<T> beanClass)throws SQLException {
        //创建Bean实例
        T instance = newInstance(beanClass);
        //获取Bean的属性描述器
        PropertyDescriptor[] pds = propertyDescriptors(beanClass);
        for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
            //获取列名
            String columnLable = rs.getMetaData().getColumnLabel(i);
            //循环解析属性描述器
            for (PropertyDescriptor pd : pds) {
                //解析匹配字段
                if (hasColumnLable(columnLable,pd,beanClass)){
                    //赋值操作
                    processColumn(rs,pd,columnLable,instance);
                }
            }
        }
        return instance;
    }

    /**
     * 根据Class对象创建实例
     */
    private static <T> T newInstance(Class<T> beanClass){
        try {
            return  beanClass.getConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过内省得到所有的属性描述器
     * @param beanClass bean的Class对象
     * @return 属性描述器数组
     * @throws SQLException sql异常
     */
    private static PropertyDescriptor[] propertyDescriptors(Class<?> beanClass)  {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(beanClass, Object.class);
            //从beanInfo获取属性描述器
            return beanInfo.getPropertyDescriptors();
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据属性描述器解析是否存在此列名
     * @param pd 属性描述器
     * @param beanClass bean的Class对象
     * @return true表示存在此列，false则不存在
     * @throws SQLException sql异常
     */
    private static boolean hasColumnLable(String columnLable,
                                   PropertyDescriptor pd,Class<?> beanClass) throws SQLException{
        try {
            //属性字段名
            String fieldNmae = pd.getName();
            //获取Field字段实例
            Field field = beanClass.getDeclaredField(fieldNmae);
            //获取字段上的Column注解
            if (field.isAnnotationPresent(Column.class)){
                fieldNmae = field.getAnnotation(Column.class).value();
            }
            //比较列名和字段名
            return fieldNmae.equalsIgnoreCase(columnLable);
        } catch (NoSuchFieldException e) {
            throw new SQLException("Cannot resolve " + pd.getName() + ": " + e.getMessage());
        }
    }

    /**
     * 根据字段类型获取rs的值
     * @param pd 属性描述器
     * @param columnLabel 列的标签
     * @param rs 结果集
     * @return Object
     * @throws SQLException sql异常
     */
    private static void  processColumn(ResultSet rs,PropertyDescriptor pd,
                                       String columnLabel,Object instance){
        try {
            //通过rs获取value
            Object value = rs.getObject(columnLabel);
            //执行类型转换(例如日期不匹配)
            if (value!=null){
                for (TypeConverter converter:loader){
                    if (converter.supports(pd.getPropertyType())){
                        value = converter.convert(pd.getPropertyType(),value);
                        break;
                    }
                }
            }
            //注意：当value
            if (pd.getPropertyType().isPrimitive() && value == null){
                //如果当前这个是基本类型并且值为空就返回不操作
                return;
            }
            //将value赋值给field,获取set方法进行赋值
            pd.getWriteMethod().invoke(instance,value);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
